'''

@File : m3u8FileHandler.py

@Author: 爸爸

@Date : 2019/3/29

@Desc :原始链接为非标准m3u8，以某游戏公司CEO工作群发的福利视频链接为例。此m3u8是多了一个地址隐藏操作防止屏蔽。即通过原始链接访问到的m3u8文件中不是ts文件列表，而是真正的m3u8地址。
m3u8流媒体原理：
标准m3u8，通过http访问后，返回一个.m3u8格式的文件，打开文件后会发现内部是一个.ts格式的文件列表。对文件列表内的.ts路径进行拼接，再通过http逐个访问即可将所有.ts文件下载（缓存），通过视频播放器根据顺序进行播放。
下载方式根据流媒体原理，将ts文件保存到本地之后，进行合并转码，然后就可以以常见格式获取到视频了。
由于视频比较敏感，故不上传，只保留原始链接。如果链接失效，请更换其他链接，来研究m3u8流媒体原理。


'''
import os
import time
import m3u8
import requests
from glob import iglob
from natsort import natsorted
from concurrent.futures import ThreadPoolExecutor


def get_ts_url(m3u8_url):
    m3u8_obj = m3u8.load(m3u8_url)
    base_uri = m3u8_obj.base_uri

    for seg in m3u8_obj.segments:
        yield base_uri + seg.uri


def download_ts(urlinfo):
    url, ts_name = urlinfo
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36', }
    Res = requests.get(url, headers=headers)
    with open(ts_name, 'wb') as fp:
        fp.write(Res.content)


def combin_ts(ts_dir=os.path.dirname(__file__)):
    ts_path = os.path.join(ts_dir, '*.ts')
    new_path = os.path.join(ts_dir, 'new')  # 防止被处理,写判断多余，直接重命名即可
    with open(new_path, 'wb') as fn:
        for ts in natsorted(iglob(ts_path)):
            with open(ts, 'rb') as ft:
                scline = ft.read()
                fn.write(scline)
    for ts in natsorted(iglob(ts_path)):  # 删除下载的ts文件
        os.remove(ts)
    os.rename(new_path, new_path + '.ts')


if __name__ == '__main__':
    # m3u8_url = 'https://dadi-yun.com/20190305/1826_4d2ec220/index.m3u8?from=' #妈的这是个假地址，需要解析一下才有上边的地址
    m3u8_url = 'https://dadi-yun.com/20190305/1826_4d2ec220/800k/hls/index.m3u8'
    urls = get_ts_url(m3u8_url)

    threadpool = ThreadPoolExecutor(max_workers=10)
    start = time.time()

    for index, url in enumerate(urls, 1):
        threadpool.submit(download_ts, [url, f'{index}.ts'])  # 强制设置文件以索引命名
    threadpool.shutdown()

    end = time.time()

    print (f"用时:{end-start}")
    start = time.time()
    combin_ts()
    end = time.time()
    print (f"用时:{end-start}")